﻿using System.Linq;

namespace Sidvall.CodeGenerator
{
    public class DomainObjectProperty
    {
        #region Public Members

        public string Tag { get; set; }
        public string DefaultValue { get; set; }
        public string DefaultValueInDataStore { get; set; }
        public string JavaScriptStringFormat { get; set; }
        public string DeserializeFormat { get; set; }
        public string StringFormat { get; set; }
        public string ValueFormat { get; set; }
        public string ValueFormatInDataStore { get; set; }
        public string ConstraintName { get; set; }
        public string Comment { get; set; }
        public int? MaxLength { get; set; }
        public byte? MaxDecimalCount { get; set; }
        public decimal? MaxValue { get; set; }
        public decimal? MinValue { get; set; }
        public bool? IsValueTypeInDataStore { get; set; }
        public bool? IsValueTypeInWeb { get; set; }
        public bool? IsComputed { get; set; }
        public bool? IsComputedInDataStore { get; set; }
        public bool? IsIdentityInDataStore { get; set; }
        public bool? IsKey { get; set; }
        public bool? TrimStringValue { get; set; }
        public ConcurrencyMode? ConcurrencyMode { get; set; }
        public DomainObject DomainObject { get; internal set; }

        #region DomainObjectPropertyFilter

        private bool _DomainObjectPropertyFilterLoaded = false;
        private DomainObjectProperty _DomainObjectPropertyFilter;
        public DomainObjectProperty DomainObjectPropertyFilter
        {
            get
            {
                if (!_DomainObjectPropertyFilterLoaded)
                {
                    if (this.DomainObject?.DomainModel?.DomainModelFilter == null)
                    {
                        _DomainObjectPropertyFilter = null;
                    }
                    else
                    {
                        var name = GetFullName(this.DomainObject.FullName, _Name);
                        var mapping = (from o in this.DomainObject.DomainModel.DomainModelFilter.DomainObjectPropertyMappings
                                       where o.PropertyFullName.Equals(name, true, System.StringComparison.OrdinalIgnoreCase)
                                       select o).FirstOrDefault();
                        this.DomainObjectPropertyFilter = mapping?.Property;
                    }
                    _DomainObjectPropertyFilterLoaded = true;
                }
                return _DomainObjectPropertyFilter;
            }
            private set
            {
                if (value != null)
                {
                    _DomainObjectPropertyFilter = value;
                }
                else if (_DomainObjectPropertyFilter != null)
                {
                    _DomainObjectPropertyFilter = null;
                }
                _DomainObjectPropertyFilterLoaded = false;
            }
        }

        #endregion
        #region IsIdentity

        private bool? _IsIdentity;
        public bool? IsIdentity
        {
            get
            {
                return _IsIdentity;
            }
            set
            {
                _IsIdentity = value;
                if (_IsIdentity == true)
                    this.IsNullable = true;
            }
        }

        #endregion
        #region IsNullable

        private bool? _IsNullable;
        public bool? IsNullable
        {
            get
            {
                if (this.DomainObjectPropertyFilter?.IsNullable != null)
                    return this.DomainObjectPropertyFilter.IsNullable;
                return _IsNullable;
            }
            set
            {
                if (this.IsIdentityResolved)
                    _IsNullable = true;
                else
                    _IsNullable = value;
                OnIsNullableChanged();
            }
        }

        #endregion
        #region IsNullableInDataStore

        private bool? _IsNullableInDataStore;
        public bool? IsNullableInDataStore
        {
            get
            {
                if (this.DomainObjectPropertyFilter?.IsNullableInDataStore != null)
                    return this.DomainObjectPropertyFilter.IsNullableInDataStore;
                return _IsNullableInDataStore;
            }
            set
            {
                _IsNullableInDataStore = value;
                OnIsNullableInDataStoreChanged();
            }
        }

        #endregion
        #region IsValueType

        private bool? _IsValueType;
        public bool? IsValueType
        {
            get
            {
                if (this.DomainObjectPropertyFilter?.IsValueType != null)
                    return this.DomainObjectPropertyFilter.IsValueType;
                return _IsValueType;
            }
            set
            {
                _IsValueType = value;
            }
        }

        #endregion
        #region Name

        private string _Name;
        public string Name
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(this.DomainObjectPropertyFilter?.Name))
                    return this.DomainObjectPropertyFilter.Name;
                return _Name;
            }
            set
            {
                _Name = value;
            }
        }

        #endregion
        #region NameInDataStore

        private string _NameInDataStore;
        public string NameInDataStore
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(this.DomainObjectPropertyFilter?.NameInDataStore))
                    return this.DomainObjectPropertyFilter.NameInDataStore;
                return _NameInDataStore;
            }
            set
            {
                _NameInDataStore = value;
            }
        }

        #endregion
        #region TypeName

        private string _TypeName;
        public string TypeName
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(this.DomainObjectPropertyFilter?.TypeName))
                    return this.DomainObjectPropertyFilter.TypeName;
                return _TypeName;
            }
            set
            {
                _TypeName = value;
                this.NotNullableTypeName = null;
                this.NullableTypeName = null;
                this.TypeNameInWeb = null;
            }
        }

        #endregion
        #region TypeNameInDataStore

        private string _TypeNameInDataStore;
        public string TypeNameInDataStore
        {
            get
            {
                if (!string.IsNullOrWhiteSpace(this.DomainObjectPropertyFilter?.TypeNameInDataStore))
                    return this.DomainObjectPropertyFilter.TypeNameInDataStore;
                return _TypeNameInDataStore;
            }
            set
            {
                _TypeNameInDataStore = value;
                this.NotNullableTypeNameInDataStore = null;
                this.NullableTypeNameInDataStore = null;
            }
        }

        #endregion
        #region TypeNameInWeb

        private string _TypeNameInWeb;
        public string TypeNameInWeb
        {
            get
            {
                if (_TypeNameInWeb == null)
                    this.TypeNameInWeb = TypeMapper.GetTypeNameInWeb(this.PropertyType);
                return _TypeNameInWeb;
            }
            private set
            {
                _TypeNameInWeb = value;
                this.NotNullableTypeNameInWeb = null;
                this.NullableTypeNameInWeb = null;
            }
        }

        #endregion

        #region ChildRelations

        private DomainObjectRelationCollection _ChildRelations;
        public DomainObjectRelationCollection ChildRelations
        {
            get
            {
                if (_ChildRelations == null)
                {
                    if (this.DomainObject == null)
                        return null;
                    _ChildRelations = new DomainObjectRelationCollection();
                    foreach (var relation in this.DomainObject.ChildRelations)
                    {
                        foreach (var item in relation.Fields)
                        {
                            if (item.SourceProperty.Name == this.Name)
                            {
                                if (!_ChildRelations.Contains(relation.Key))
                                    _ChildRelations.Add(relation);
                                break;
                            }
                        }
                    }
                }
                return _ChildRelations;
            }
            private set
            {
                _ChildRelations = value;
                this.ChildRelationProperties = null;
            }
        }

        #endregion
        #region ChildRelationProperties

        private DomainObjectRelationPropertyCollection _ChildRelationProperties;
        public DomainObjectRelationPropertyCollection ChildRelationProperties
        {
            get
            {
                System.Collections.Generic.HashSet<string> index;

                if (_ChildRelationProperties == null)
                {
                    if (this.ChildRelations == null)
                        return null;
                    index = new System.Collections.Generic.HashSet<string>();
                    _ChildRelationProperties = new DomainObjectRelationPropertyCollection();
                    foreach (var relation in this.ChildRelations)
                    {
                        foreach (var item in relation.Fields)
                        {
                            if (item.SourceProperty.Name == this.Name)
                            {
                                if (!index.Contains(item.RelatedProperty.FullName))
                                {
                                    index.Add(item.RelatedProperty.FullName);
                                    _ChildRelationProperties.Add(item.RelatedProperty);
                                }
                            }
                        }
                    }
                }
                return _ChildRelationProperties;
            }
            private set
            {
                _ChildRelationProperties = value;
            }
        }

        #endregion
        #region ConcurrencyModeResolved

        public ConcurrencyMode ConcurrencyModeResolved
        {
            get
            {
                if (this.ConcurrencyMode == null)
                    return CodeGenerator.ConcurrencyMode.None;
                return this.ConcurrencyMode.Value;
            }
        }

        #endregion
        #region Constraint

        public Constraint Constraint
        {
            get
            {
                if (string.IsNullOrWhiteSpace(this.ConstraintName))
                    return null;
                if (this.DomainObject == null)
                    return null;
                if (this.DomainObject.DomainModel == null)
                    return null;
                return this.DomainObject.DomainModel.Constraints.FindByName(this.ConstraintName);
            }
        }

        #endregion
        #region DefaultValueResolved

        public string DefaultValueResolved
        {
            get
            {
                if (string.IsNullOrWhiteSpace(this.DefaultValue))
                {
                    if (this.IsNullableResolved)
                        return "null";
                    return TypeMapper.GetDefaultValue(this.PropertyType, this.IsNullableResolved);
                }
                return this.DefaultValue;
            }
        }

        #endregion
        #region DefaultValueInDataStoreResolved

        public string DefaultValueInDataStoreResolved
        {
            get
            {
                if (string.IsNullOrWhiteSpace(this.DefaultValueInDataStore))
                {
                    if (this.IsNullableInDataStoreResolved)
                        return "null";
                    return TypeMapper.GetDefaultValue(this.PropertyTypeInDataStore, this.IsNullableInDataStoreResolved);
                }
                return this.DefaultValueInDataStore;
            }
        }

        #endregion
        #region ExampleValue

        public string ExampleValue
        {
            get
            {
                return TypeMapper.GetExampleValue(this.PropertyType);
            }
        }

        #endregion
        #region FullName

        public string FullName
        {
            get
            {
                return GetFullName(this.DomainObject?.FullName, this.Name);
            }
        }

        #endregion
        #region IsArray

        public bool IsArray
        {
            get
            {
                if (this.NotNullableTypeName.EndsWith("[]", System.StringComparison.OrdinalIgnoreCase))
                    return true;
                return false;
            }
        }

        #endregion
        #region IsComputedResolved

        public bool IsComputedResolved
        {
            get
            {
                if (this.IsComputed != null)
                    return this.IsComputed.Value;
                return false;
            }
        }

        #endregion
        #region IsComputedInDataStoreResolved

        public bool IsComputedInDataStoreResolved
        {
            get
            {
                if (this.IsComputedInDataStore != null)
                    return this.IsComputedInDataStore.Value;
                return false;
            }
        }

        #endregion
        #region IsEnum

        private bool _IsEnum;
        public bool IsEnum
        {
            get
            {
                return _IsEnum;
            }
            private set
            {
                _IsEnum = value;
            }
        }

        #endregion
        #region IsGenerated

        public bool IsGenerated
        {
            get
            {
                if ((this.IsComputedResolved) || (this.IsIdentityResolved))
                    return true;
                return false;
            }
        }

        #endregion
        #region IsGeneratedInDataStore

        public bool IsGeneratedInDataStore
        {
            get
            {
                if ((this.IsComputedInDataStoreResolved) || (this.IsIdentityInDataStoreResolved))
                    return true;
                return false;
            }
        }

        #endregion
        #region IsInRelation

        public bool IsInRelation
        {
            get
            {
                if (this.ChildRelations.Count > 0)
                    return true;
                if (this.ParentRelations.Count > 0)
                    return true;
                return false;
            }
        }

        #endregion
        #region IsInteger

        public bool IsInteger
        {
            get
            {
                switch (this.PropertyType)
                {
                    case PropertyType.Byte:
                    case PropertyType.Int16:
                    case PropertyType.Int32:
                    case PropertyType.Int64:
                    case PropertyType.SByte:
                    case PropertyType.UInt16:
                    case PropertyType.UInt32:
                    case PropertyType.UInt64:
                        return true;
                    default:
                        return false;
                }
            }
        }

        #endregion
        #region IsIdentityResolved

        public bool IsIdentityResolved
        {
            get
            {
                if (this.IsIdentity != null)
                    return this.IsIdentity.Value;
                return false;
            }
        }

        #endregion
        #region IsIdentityInDataStoreResolved

        public bool IsIdentityInDataStoreResolved
        {
            get
            {
                if (this.IsIdentityInDataStore != null)
                    return this.IsIdentityInDataStore.Value;
                return false;
            }
        }

        #endregion
        #region IsNullableResolved

        public bool IsNullableResolved
        {
            get
            {
                if (this.IsNullable != null)
                    return this.IsNullable.Value;
                return false;
            }
        }

        #endregion
        #region IsNullableInDataStoreResolved

        public bool IsNullableInDataStoreResolved
        {
            get
            {
                if (this.IsNullableInDataStore != null)
                    return this.IsNullableInDataStore.Value;
                return false;
            }
        }

        #endregion
        #region IsKeyResolved

        public bool IsKeyResolved
        {
            get
            {
                if (this.IsKey != null)
                    return this.IsKey.Value;
                return false;
            }
        }

        #endregion
        #region IsString

        public bool IsString
        {
            get
            {
                switch (this.PropertyType)
                {
                    case PropertyType.String:
                        return true;
                    default:
                        return false;
                }
            }
        }

        #endregion
        #region IsValueTypeResolved

        public bool IsValueTypeResolved
        {
            get
            {
                if (this.IsValueType != null)
                    return this.IsValueType.Value;
                return false;
            }
        }

        #endregion
        #region IsValueTypeInDataStoreResolved

        public bool IsValueTypeInDataStoreResolved
        {
            get
            {
                if (this.IsValueTypeInDataStore != null)
                    return this.IsValueTypeInDataStore.Value;
                return false;
            }
        }

        #endregion
        #region IsValueTypeInWebResolved

        public bool IsValueTypeInWebResolved
        {
            get
            {
                if (this.IsValueTypeInWeb != null)
                    return this.IsValueTypeInWeb.Value;
                return false;
            }
        }

        #endregion
        #region NotNullableTypeName

        private string _NotNullableTypeName;
        public string NotNullableTypeName
        {
            get
            {
                if (_NotNullableTypeName == null)
                    _NotNullableTypeName = TypeMapper.GetTypeName(this.TypeName, false);
                return _NotNullableTypeName;
            }
            private set
            {
                _NotNullableTypeName = value;
                _PropertyType = null;
            }
        }

        #endregion
        #region NotNullableTypeNameInDataStore

        private string _NotNullableTypeNameInDataStore;
        public string NotNullableTypeNameInDataStore
        {
            get
            {
                if (_NotNullableTypeNameInDataStore == null)
                    _NotNullableTypeNameInDataStore = TypeMapper.GetTypeName(this.TypeNameInDataStore, false);
                return _NotNullableTypeNameInDataStore;
            }
            private set
            {
                _NotNullableTypeNameInDataStore = value;
                _PropertyTypeInDataStore = null;
            }
        }

        #endregion
        #region NotNullableTypeNameInWeb

        private string _NotNullableTypeNameInWeb;
        public string NotNullableTypeNameInWeb
        {
            get
            {
                if (_NotNullableTypeNameInWeb == null)
                    _NotNullableTypeNameInWeb = this.TypeNameInWeb;
                return _NotNullableTypeNameInWeb;
            }
            private set
            {
                _NotNullableTypeNameInWeb = value;
            }
        }

        #endregion
        #region NullableTypeName

        private string _NullableTypeName;
        public string NullableTypeName
        {
            get
            {
                if (_NullableTypeName == null)
                {
                    if (this.IsValueTypeResolved)
                        _NullableTypeName = TypeMapper.GetTypeName(this.TypeName, true);
                    else
                        _NullableTypeName = this.TypeName;
                }
                return _NullableTypeName;
            }
            private set
            {
                _NullableTypeName = value;
            }
        }

        #endregion
        #region NullableTypeNameInDataStore

        private string _NullableTypeNameInDataStore;
        public string NullableTypeNameInDataStore
        {
            get
            {
                if (_NullableTypeNameInDataStore == null)
                {
                    if (this.IsValueTypeInDataStoreResolved)
                        _NullableTypeNameInDataStore = TypeMapper.GetTypeName(this.TypeNameInDataStore, true);
                    else
                        _NullableTypeNameInDataStore = this.TypeNameInDataStore;
                }
                return _NullableTypeNameInDataStore;
            }
            private set
            {
                _NullableTypeNameInDataStore = value;
            }
        }

        #endregion
        #region NullableTypeNameInWeb

        private string _NullableTypeNameInWeb;
        public string NullableTypeNameInWeb
        {
            get
            {
                if (_NullableTypeNameInWeb == null)
                    _NullableTypeNameInWeb = this.TypeNameInWeb;
                return _NullableTypeNameInWeb;
            }
            private set
            {
                _NullableTypeNameInWeb = value;
            }
        }

        #endregion
        #region ParentRelations

        private DomainObjectRelationCollection _ParentRelations;
        public DomainObjectRelationCollection ParentRelations
        {
            get
            {
                if (_ParentRelations == null)
                {
                    if (this.DomainObject == null)
                        return null;
                    _ParentRelations = new DomainObjectRelationCollection();
                    foreach (var relation in this.DomainObject.ParentRelations)
                    {
                        foreach (var item in relation.Fields)
                        {
                            if (item.SourceProperty.Name == this.Name)
                            {
                                if (!_ParentRelations.Contains(relation.Key))
                                    _ParentRelations.Add(relation);
                                break;
                            }
                        }
                    }
                }
                return _ParentRelations;
            }
            private set
            {
                _ParentRelations = value;
            }
        }

        #endregion
        #region PropertyType

        private PropertyType? _PropertyType;
        public PropertyType PropertyType
        {
            get
            {
                if (_PropertyType == null)
                    this.PropertyType = TypeMapper.GetPropertyType(this.NotNullableTypeName);
                return _PropertyType.Value;
            }
            private set
            {
                _PropertyType = value;
                this.TypeNameInWeb = null;
            }
        }

        #endregion
        #region PropertyTypeInDataStore

        private PropertyType? _PropertyTypeInDataStore;
        public PropertyType PropertyTypeInDataStore
        {
            get
            {
                if (_PropertyTypeInDataStore == null)
                    _PropertyTypeInDataStore = TypeMapper.GetPropertyType(this.NotNullableTypeNameInDataStore);
                return _PropertyTypeInDataStore.Value;
            }
        }

        #endregion
        #region TrimStringValueResolved

        public bool TrimStringValueResolved
        {
            get
            {
                if (this.TrimStringValue != null)
                    return this.TrimStringValue.Value;
                return true;
            }
        }

        #endregion

        #region ClearCache

        public void ClearCache()
        {
            this.DomainObjectPropertyFilter = null;
            this.ChildRelations = null;
            this.ParentRelations = null;
            this.NotNullableTypeName = null;
            this.NotNullableTypeNameInDataStore = null;
            this.NullableTypeName = null;
            this.NullableTypeNameInDataStore = null;
            this.TypeNameInWeb = null;

        }

        #endregion
        #region GetDeserializeFormat

        public string GetDeserializeFormat(string value)
        {
            return GetDeserializeFormat(value, this.DeserializeFormat, null, null, false);
        }
        public string GetDeserializeFormat(string value, bool? isNullable)
        {
            return GetDeserializeFormat(value, this.DeserializeFormat, isNullable, null, false);
        }
        public string GetDeserializeFormat(string value, string deserializeFormat)
        {
            return GetDeserializeFormat(value, deserializeFormat, null, null, false);
        }
        public string GetDeserializeFormat(string value, string deserializeFormat, bool? isNullable, bool? useDeserializeFormat, bool? useDefaultValue)
        {
            if (isNullable == null)
                isNullable = this.IsNullableResolved;
            if (useDeserializeFormat == null)
                useDeserializeFormat = !string.IsNullOrWhiteSpace(this.DeserializeFormat);
            if (useDefaultValue == null)
                useDefaultValue = !string.IsNullOrWhiteSpace(this.DefaultValue);
            if (useDefaultValue == true)
            {
                if (useDeserializeFormat == true)
                {
                    if ((this.IsEnum) && (!deserializeFormat.EndsWith(".Value", System.StringComparison.OrdinalIgnoreCase)))
                        return string.Format(System.Globalization.CultureInfo.InvariantCulture, deserializeFormat, value) + ".Value";
                    return string.Format(System.Globalization.CultureInfo.InvariantCulture, deserializeFormat, value);
                }
                else
                {
                    if (this.IsEnum)
                    {
                        value += ".ToEnum(" + this.DefaultValue + ")";
                    }
                    else
                    {
                        switch (this.PropertyType)
                        {
                            case PropertyType.Boolean:
                                value += ".ToBoolean(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Char:
                                value += ".ToChar(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.DateTime:
                                value += ".ToDateTime(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.DateTimeOffset:
                                value += ".ToDateTimeOffset(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Decimal:
                                value += ".ToDecimal(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Double:
                                value += ".ToDouble(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Byte:
                                value += ".ToByte(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Int16:
                                value += ".ToInt16(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Int32:
                                value += ".ToInt32(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Int64:
                                value += ".ToInt64(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Single:
                                value += ".ToSingle(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.TimeSpan:
                                value += ".ToTimeSpan(" + this.DefaultValue + ")";
                                break;
                            case PropertyType.Guid:
                                value += ".ToGuid(" + this.DefaultValue + ")";
                                break;
                            default:
                                return value;
                        }
                    }
                    return value;
                }
            }
            else
            {
                if (useDeserializeFormat == true)
                {
                    if ((this.IsEnum) && (!deserializeFormat.EndsWith(".Value", System.StringComparison.OrdinalIgnoreCase)))
                        return string.Format(System.Globalization.CultureInfo.InvariantCulture, deserializeFormat, value) + ".Value";
                    return string.Format(System.Globalization.CultureInfo.InvariantCulture, deserializeFormat, value);
                }
                else
                {
                    if (this.IsEnum)
                    {
                        value += ".ToNullableEnum<" + this.NotNullableTypeName + ">()";
                    }
                    else
                    {
                        switch (this.PropertyType)
                        {
                            case PropertyType.Boolean:
                                value += ".ToNullableBoolean()";
                                break;
                            case PropertyType.Char:
                                value += ".ToNullableChar()";
                                break;
                            case PropertyType.DateTime:
                                value += ".ToNullableDateTime()";
                                break;
                            case PropertyType.DateTimeOffset:
                                value += ".ToNullableDateTimeOffset()";
                                break;
                            case PropertyType.Decimal:
                                value += ".ToNullableDecimal()";
                                break;
                            case PropertyType.Double:
                                value += ".ToNullableDouble()";
                                break;
                            case PropertyType.Byte:
                                value += ".ToNullableByte()";
                                break;
                            case PropertyType.Int16:
                                value += ".ToNullableInt16()";
                                break;
                            case PropertyType.Int32:
                                value += ".ToNullableInt32()";
                                break;
                            case PropertyType.Int64:
                                value += ".ToNullableInt64()";
                                break;
                            case PropertyType.Single:
                                value += ".ToNullableSingle()";
                                break;
                            case PropertyType.TimeSpan:
                                value += ".ToNullableTimeSpan()";
                                break;
                            case PropertyType.Guid:
                                value += ".ToNullableGuid()";
                                break;
                            default:
                                return value;
                        }
                    }
                    if (!isNullable.Value)
                        value += ".Value";
                    return value;
                }
            }
        }

        #endregion
        #region GetFullName

        public static string GetFullName(string className, string name)
        {
            if (string.IsNullOrWhiteSpace(className))
                return name;
            return string.Join(".", className, name);
        }

        #endregion
        #region GetNotNullableValue

        public string GetNotNullableValue()
        {
            return GetNotNullableValue(this.Name);
        }

        public string GetNotNullableValue(string value)
        {
            if ((this.IsNullableResolved) && (this.IsValueTypeResolved))
                return value + ".Value";
            return value;
        }

        #endregion
        #region GetJavaScriptStringFormat

        public string GetJavaScriptStringFormat(string value)
        {
            return GetJavaScriptStringFormat(value, this.JavaScriptStringFormat, null, null);
        }
        public string GetJavaScriptStringFormat(string value, bool? isNullable)
        {
            return GetJavaScriptStringFormat(value, this.JavaScriptStringFormat, isNullable, null);
        }
        public string GetJavaScriptStringFormat(string value, string javaScriptStringFormat)
        {
            return GetJavaScriptStringFormat(value, javaScriptStringFormat, null, null);
        }
        public string GetJavaScriptStringFormat(string value, string javaScriptStringFormat, bool? isNullable, bool? useJavaScriptStringFormat)
        {
            if (isNullable == null)
                isNullable = this.IsNullableResolved;
            if (useJavaScriptStringFormat == null)
                useJavaScriptStringFormat = !string.IsNullOrWhiteSpace(this.JavaScriptStringFormat);
            if (!useJavaScriptStringFormat.Value)
            {
                if (this.IsString)
                    return value;
                else if (this.IsEnum)
                    return value + ".toString()";
                else if ((isNullable.Value) || (!this.IsValueTypeResolved) || (this.PropertyType == CodeGenerator.PropertyType.Boolean))
                    return value + ".toString()";
                else
                    return value + ".toString()";
            }
            return string.Format(System.Globalization.CultureInfo.InvariantCulture, javaScriptStringFormat, value);
        }

        #endregion
        #region GetStringFormat

        public string GetStringFormat(string value)
        {
            return GetStringFormat(value, this.StringFormat, null, null);
        }
        public string GetStringFormat(string value, bool? isNullable)
        {
            return GetStringFormat(value, this.StringFormat, isNullable, null);
        }
        public string GetStringFormat(string value, string stringFormat)
        {
            return GetStringFormat(value, stringFormat, null, null);
        }
        public string GetStringFormat(string value, string stringFormat, bool? isNullable, bool? useStringFormat)
        {
            if (isNullable == null)
                isNullable = this.IsNullableResolved;
            if (useStringFormat == null)
                useStringFormat = !string.IsNullOrWhiteSpace(this.StringFormat);
            if (!useStringFormat.Value)
            {
                if (this.IsString)
                    return value;
                else if (this.IsEnum)
                    return value + ".ToString()";
                else if (this.PropertyType == CodeGenerator.PropertyType.Boolean)
                    return value + ".ToString()";
                else if (this.PropertyType == CodeGenerator.PropertyType.Guid)
                    return value + ".ToString()";
                else if ((isNullable.Value) || (!this.IsValueTypeResolved))
                    return value + ".ToString()";
                else
                    return value + ".ToString(System.Globalization.CultureInfo.InvariantCulture)";
            }
            return string.Format(System.Globalization.CultureInfo.InvariantCulture, stringFormat, value);
        }

        #endregion
        #region GetValueFormat

        public string GetValueFormat(string value)
        {
            return GetValueFormat(value, this.ValueFormat);
        }
        public string GetValueFormat(string value, string valueFormat)
        {
            return GetValueFormat(value, valueFormat, null);
        }
        public string GetValueFormat(string value, string valueFormat, bool? useValueFormat)
        {
            if (useValueFormat == null)
                useValueFormat = !string.IsNullOrWhiteSpace(this.ValueFormat);
            if (!useValueFormat.Value)
            {
                if (this.IsEnum)
                {
                    return "(" + this.TypeName + ")" + value;
                }
                return value;
            }
            return string.Format(System.Globalization.CultureInfo.InvariantCulture, valueFormat, value);
        }

        #endregion
        #region GetValueFormatInDataStore

        public string GetValueFormatInDataStore(string value)
        {
            return GetValueFormatInDataStore(value, this.ValueFormatInDataStore);
        }
        public string GetValueFormatInDataStore(string value, string valueFormat)
        {
            return GetValueFormatInDataStore(value, valueFormat, null);
        }
        public string GetValueFormatInDataStore(string value, string valueFormat, bool? useValueFormat)
        {
            if (useValueFormat == null)
                useValueFormat = !string.IsNullOrWhiteSpace(this.ValueFormatInDataStore);
            if (!useValueFormat.Value)
            {
                if (this.IsEnum)
                {
                    return "(" + this.TypeNameInDataStore + ")" + value;
                }
                return value;
            }
            return string.Format(System.Globalization.CultureInfo.InvariantCulture, valueFormat, value);
        }

        #endregion
        #region Import

        public void Import(DomainObjectProperty item)
        {
            if (item == null)
                return;

            if (item.Name != null)
                this.Name = item.Name;
            if (item.NameInDataStore != null)
                this.NameInDataStore = item.NameInDataStore;
            if (item.DefaultValue != null)
                this.DefaultValue = item.DefaultValue;
            if (item.DefaultValueInDataStore != null)
                this.DefaultValueInDataStore = item.DefaultValueInDataStore;
            if (item.JavaScriptStringFormat != null)
                this.JavaScriptStringFormat = item.JavaScriptStringFormat;
            if (item.DeserializeFormat != null)
                this.DeserializeFormat = item.DeserializeFormat;
            if (item.StringFormat != null)
                this.StringFormat = item.StringFormat;
            if (item.ValueFormat != null)
                this.ValueFormat = item.ValueFormat;
            if (item.ValueFormatInDataStore != null)
                this.ValueFormatInDataStore = item.ValueFormatInDataStore;
            if (item.MaxLength != null)
                this.MaxLength = item.MaxLength;
            if (item.IsValueType != null)
                this.IsValueType = item.IsValueType;
            if (item.IsValueTypeInDataStore != null)
                this.IsValueTypeInDataStore = item.IsValueTypeInDataStore;
            if (item.IsComputed != null)
                this.IsComputed = item.IsComputed;
            if (item.IsComputedInDataStore != null)
                this.IsComputedInDataStore = item.IsComputedInDataStore;
            if (item.IsIdentity != null)
                this.IsIdentity = item.IsIdentity;
            if (item.IsIdentityInDataStore != null)
                this.IsIdentityInDataStore = item.IsIdentityInDataStore;
            if (item.IsKey != null)
                this.IsKey = item.IsKey;
            if (item.IsNullable != null)
                this.IsNullable = item.IsNullable;
            if (item.IsNullableInDataStore != null)
                this.IsNullableInDataStore = item.IsNullableInDataStore;
            if (item.TypeName != null)
                this.TypeName = item.TypeName;
            if (item.TypeNameInDataStore != null)
                this.TypeNameInDataStore = item.TypeNameInDataStore;
            if (item.ConcurrencyMode != null)
                this.ConcurrencyMode = item.ConcurrencyMode;
        }

        #endregion
        #region SetPropertyAsCultureItem

        public void SetPropertyAsCultureItem()
        {
            if (this.IsNullableInDataStoreResolved)
            {
                SetPropertyAsCustomType("Sidvall.Globalization.CultureValueCollection", "new Sidvall.Globalization.CultureValueCollection()",
                    null, null, null,
                    "Sidvall.Globalization.CultureValueCollection.Deserialize({0})", "Sidvall.Globalization.CultureValueCollection.Serialize({0})");
            }
            else
            {
                SetPropertyAsCustomType("Sidvall.Globalization.CultureValueCollection", "new Sidvall.Globalization.CultureValueCollection()",
                    null, null, null,
                    "Sidvall.Globalization.CultureValueCollection.Deserialize({0})", "Sidvall.Globalization.CultureValueCollection.Serialize({0}, string.Empty)");
            }
        }

        #endregion
        #region SetPropertyAsCustomType

        public void SetPropertyAsCustomType(string typeName, string defaultValue, bool? isNullable,
            string deserializeFormat, string stringFormat, string valueFormat, string valueFormatInDataStore)
        {
            this.IsEnum = false;
            this.IsValueType = false;
            this.TypeName = typeName;
            this.DefaultValue = defaultValue;
            this.DeserializeFormat = deserializeFormat;
            this.StringFormat = stringFormat;
            this.ValueFormat = valueFormat;
            this.ValueFormatInDataStore = valueFormatInDataStore;
            if (isNullable != null)
            {
                this.IsNullable = isNullable;
            }
            else
            {
                OnIsNullableChanged();
            }
            this.PropertyType = PropertyType.Object;
            foreach (var item in this.ChildRelationProperties)
                item.SetPropertyAsCustomType(typeName, defaultValue, isNullable, deserializeFormat, stringFormat, valueFormat, valueFormatInDataStore);
        }

        #endregion
        #region SetPropertyAsEnum

        public void SetPropertyAsEnum(string enumName, string defaultValue, bool? isNullable)
        {
            PropertyType propertyType;

            if (this.IsInteger)
                propertyType = this.PropertyType;
            else
                propertyType = CodeGenerator.PropertyType.Int32;
            this.IsEnum = true;
            this.IsValueType = true;
            this.TypeName = enumName;
            this.DefaultValue = defaultValue;
            if (isNullable != null)
            {
                this.IsNullable = isNullable;
            }
            else
            {
                OnIsNullableChanged();
            }
            this.PropertyType = propertyType;
            foreach (var item in this.ChildRelationProperties)
                item.SetPropertyAsEnum(enumName, defaultValue, isNullable);
        }

        #endregion
        #region SetPropertyName

        public void SetPropertyName(string newPropertyName)
        {
            this.Name = newPropertyName;
            foreach (var item in this.ChildRelationProperties)
                item.SetPropertyName(newPropertyName);
            ClearCache();
        }

        #endregion
        #region SetPropertyValues

        public void SetPropertyValues(string defaultValue)
        {
            this.DefaultValue = defaultValue;
        }
        public void SetPropertyValues(string defaultValue, int? maxLength, decimal? minValue, decimal? maxValue, byte? maxDecimalCount)
        {
            this.DefaultValue = defaultValue;
            this.MaxLength = maxLength;
            this.MinValue = minValue;
            this.MaxValue = maxValue;
            this.MaxDecimalCount = maxDecimalCount;
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            if (this.DomainObject != null)
                return this.DomainObject.Name + "." + this.Name;
            else
                return this.Name;
        }

        #endregion

        #endregion
        #region Private Members

        #region OnIsNullableChanged

        private void OnIsNullableChanged()
        {
            if ((this.IsNullable != null) && (this.IsValueTypeResolved))
                this.TypeName = TypeMapper.GetTypeName(this.TypeName, this.IsNullable.Value);
        }

        #endregion
        #region OnIsNullableInDataStoreChanged

        private void OnIsNullableInDataStoreChanged()
        {
            if ((this.IsNullableInDataStore != null) && (this.IsValueTypeInDataStoreResolved))
                this.TypeNameInDataStore = TypeMapper.GetTypeName(this.TypeNameInDataStore, this.IsNullableInDataStore.Value);
        }

        #endregion

        #endregion
        #region Constructors

        public DomainObjectProperty()
        {
        }

        #endregion
    }
}
